在上篇文章我們簡單的介紹了 PyTorch 和 Tensorflow 的基本不同,現在我們要用使用者的角度來檢視兩個框架的不同。今天,先來看看 PyTorch 如何實踐動態計算圖。
關於自動微分的實作,PyTorch 將之包裝在一個名叫 autograd
的模組。在 autograd
模組中,計算圖其實是由許多 Function 節點所組成。計算圖中 Function 節點的建立和表示計算步驟的前後連結,可以在正向傳遞中完成。在正向傳遞中,autograd
會為每一個需要計算梯度的 torch.Tensor
對象建立一個 Function 物件,以附加的方式成為該物件屬性。此函數附加到 torch.Tensor
物件,將會在反向過程中計算梯度時所需的。雖然,這個 Function 物件名為函數,但這個 Function 在正向傳播中只是一個表示式(“expression”),需要在反向傳播時,依賴 apply()
方法執行。
但有一點需要注意的是,由於藉由運行流程所定義的計算圖,雖然具有靈活性,但每次迭代都需要重新創建計算圖,並需要使用者明確定義運算的邏輯,方能知道如何運行計算圖。這種行為的好處是我們可以根據不同的條件,使用不同的計算圖。但缺點是效能較差,因為需要在每次迭代中重新創建計算圖,也無法事先對整張計算圖做最佳化。
如前所述,反向傳播步驟是根據使用者如何正向運行的方式確定的,並且在每次迭代中可以不同。 所以現在我們來看看 PyTorch 的 autograd
如何被實踐的。首先,在這個模組中的主要元素包括:
requires_grad
方法設置為True
,方可以使用 backwards
的方法來計算並累積梯度。requres_grad = True
。可以通過呼叫 Tensor 的grad_fn
屬性來存取附加的 Funciton 物件。 Funciton 將提供如何計算歷史記錄中的梯度的訊息。為了執行反向傳播,應該呼叫元素 1 中的 backward()
方法,開始反向計算。如果 Tensor 是數值,則在呼叫 backward()
時不需要指定任何參數。但當 Tensor 是一個多維向量時,則要給定初始值。
要停止回溯計算歷史或不納入特定一個 Tensor 物件於計算圖,可以使用以下兩個方法:
1.要 exclude 一個 Tensor 物件,可以呼叫 detach()
方法。爾後,在該 Tensor 上運行的任何後續操作,都將被忽略,不會被紀錄。
2.要 exlude 一段程式碼,可以在with torch.no_grad()
context manager 中編寫這段程式碼。
以下是一個簡單的計算圖,介紹如何用 PyTorch 建立計算圖。
x = torch.ones(2, 2, requires_grad=True)
print(x) #grad_fn is None
>>> tensor([[1., 1.], [1., 1.]],
... requires_grad=True)
y = x + 2
print(y)
>>> tensor([[3., 3.],
... [3., 3.]], grad_fn=<AddBackward0>)
print(y.grad_fn)
print(x.grad_fn)
>>> <AddBackward0 object at 0x7f2caf39b1d0> #y.grad_fn
>>> None #x.grad_fn
與 optimizer 和 loss 一起使用時,進行反向傳播的步驟是:
zero_grad
方法,將所有參數的梯度緩衝區(buffer)歸零backward()
方法開始進行反向傳播step()
方法來更新權重。在這裡,optimizer 是一個 torch.nn.optim
中任一類別的物件。而 loss 則是一個 torch.Tensor
物件,其 requires_grad
為 True.
optimizer.zero_grad()
# forward implementation
# ...
loss.backwards()
optimizer.step()
當loss.backwards()
被呼叫時會發生什麼?使用者可以試著通過呼叫grad_fn
及其next_functions
方法,動態回溯。
不要在計算圖中使用 in-place operation。 PyTorch 有一種函數屬於 in-place operation 的計算。這種 in-place operation 的計算和 numpy
有點相近,也就是在不重新安置記憶體的情況下進行該 operation。這樣的 operation 不適合 autograd
module,因為 autograd
需要經常性的釋放或重新使用 附加在 Tensor 物件上的緩衝區。
原因包括:
1.in-place operation 將覆蓋 Tensor 所持有的值。
2.in-place operation 需要將計算圖重寫,這意味著在計算圖中若有一個 in-place operation,那每次進行該 operation 需要重新建立 Function 的擁有者和輸入。
規則是:
[1] PyTorch 官方文件
[2] 更詳盡的 autograd 中文介紹